home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1998 March
/
Macworld (1998-03) (Disk 1).dmg
/
Shareware World
/
Info
/
For Developers
/
GhostScript 5.10
/
MacGS-510
/
files
/
gs_ttf.ps
< prev
next >
Wrap
Text File
|
1997-08-04
|
15KB
|
462 lines
% Copyright (C) 1996, 1997 Aladdin Enterprises. All rights reserved.
%
% This file is part of Aladdin Ghostscript.
%
% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
% or distributor accepts any responsibility for the consequences of using it,
% or for whether it serves any particular purpose or works at all, unless he
% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
% License (the "License") for full details.
%
% Every copy of Aladdin Ghostscript must include a copy of the License,
% normally in a plain ASCII text file named PUBLIC. The License grants you
% the right to copy, modify and redistribute Aladdin Ghostscript, but only
% under certain conditions described in the License. Among other things, the
% License requires that the copyright notice and this notice be preserved on
% all copies.
% Support code for direct use of TrueType fonts.
% (Not needed for Type 42 fonts.)
% ---------------- Font loading machinery ---------------- %
% Augment the FONTPATH machinery so it recognizes TrueType fonts.
/.scanfontheaders where % only defined if DISKFONTS is recognized
{ pop
/.scanfontheaders [ .scanfontheaders aload pop (\000\001\000\000*) ] def
}
if
/.findnonttfontvalue /.findfontvalue load def
/.findfontvalue % <file> <key> .findfontvalue <value> true
% <file> <key> .findfontvalue false
% Closes the file in either case.
{ 1 index read pop 2 index 1 index unread 0 eq
{ % If this is a font at all, it's a TrueType font.
dup /FontType eq
{ pop closefile 42 true }
{ dup /FontName eq
{ pop .findttfontname }
{ pop closefile false }
ifelse
}
ifelse
}
{ % Not a TrueType font.
.findnonttfontvalue
}
ifelse
} bind def
/.findttfontname % <file> .findttfontname <fname> true
% <file> .findttfontname false
% Closes the file in either case.
{ .loadttfonttables
(name) findtableentry
{ dup 8 getu32 f exch setfileposition
12 getu32 string f exch readstring pop
6 findname
}
{ false
}
ifelse
f closefile end end
} bind def
% Load a font file that might be a TrueType font.
/.loadnonttfontfile /.loadfontfile load def
/.loadfontfile % <file> .loadfontfile -
{ dup read pop 2 copy unread 0 eq
{ % If this is a font at all, it's a TrueType font.
.loadttfont pop
}
{ % Not a TrueType font.
.loadnonttfontfile
}
ifelse
} bind def
% ---------------- Automatic Type 42 generation ---------------- %
% Load a TrueType font from a file as a Type 42 PostScript font.
% The thing that makes this really messy is the handling of encodings.
% There are 3 interacting tables that affect the encoding:
% 'cmap' provides multiple maps from character codes to glyph indices
% 'glyf' maps glyph indices to outlines
% 'post' maps glyph indices to glyph names (if present)
% What we need to get out of this is:
% Encoding mapping character codes to glyph names
% (the composition of cmap and post)
% CharStrings mapping glyph names to glyph indices
% (the inverse of post)
% If the post table is missing, we have to take a guess based on the cmap
% table.
/.loadttfontdict mark
/orgXUID 107 def % Aladdin Enterprises organization XUID
/maxstring 65500 def % maximum length of a PostScript string
% Define the Macintosh standard mapping from characters to glyph indices.
/MacRomanEncoding dup .findencoding def
/MacGlyphEncoding mark
/.notdef /.null /CR
MacRomanEncoding 32 95 getinterval aload pop
MacRomanEncoding 128 45 getinterval aload pop
% 143
/notequal /AE
/Oslash /infinity /plusinus /lessequal /greaterequal
/yen /mu1 /partialdiff /summation /product
/pi /integral /ordfeminine /ordmasculine /Ohm
/ae /oslash /questiondown /exclamdown /logicalnot
/radical /florin /approxequal /increment /guillemotleft
/guillemotright /ellipsis /nbspace
MacRomanEncoding 203 12 getinterval aload pop
/lozenge
MacRomanEncoding 216 24 getinterval aload pop
/applelogo
MacRomanEncoding 241 7 getinterval aload pop
/overscore
MacRomanEncoding 249 7 getinterval aload pop
% 226
/Lslash /lslash /Scaron /scaron
/Zcaron /zcaron /brokenbar /Eth /eth
/Yacute /yacute /Thorn /thorn /minus
/multiply /onesuperior /twosuperior /threesuperior /onehalf
/onequarter /threequarters /franc /Gbreve /gbreve
/Idot /Scedilla /scedilla /Cacute /cacute
/Ccaron /ccaron /dmacron
/packedarray where
{ pop counttomark packedarray exch pop }
{ ] readonly }
ifelse def
% Procedures
/getu16 % <string> <index> getu16 <integer>
{ 2 copy get 8 bitshift 3 1 roll 1 add get add
} bind def
/gets16 % <string> <index> gets16 <integer>
{ getu16 16#8000 xor 16#8000 sub
} bind def
/getu32 % <string> <index> getu32 <integer>
{ 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
} bind def
/gets32 % <string> <index> gets32 <integer>
{ getu32 dup 16#7fffffff gt { 4 { 16#40000000 sub } repeat } if
} bind def
/getrange % <offset> <length> getrange <string>
% Free variables: sfnts
{ () sfnts
{ % Stack: offset length () sfnt
dup length 4 index gt { exch pop exit } if
4 -1 roll exch length sub 3 1 roll
}
forall 3 1 roll getinterval
} bind def
/findtableentry % <name4> findtableentry <tableentry> true
% <name4> findtableentry false
% Free variables: tables
{ false 0 16 tables length 16 sub
{ % Stack: name4 false toffset
tables 1 index 4 getinterval 3 index eq
{ tables exch 16 getinterval
exch pop exch true exit
}
if pop
}
for exch pop
} bind def
/findtable % <name4> findtable <table> true
% <name4> findtable false
% Free variables: tables
{ findtableentry
{ dup 8 getu32 exch 12 getu32 getrange true }
{ false }
ifelse
} bind def
/findname % <nametable> <nameid> findname <string> true
% <nametable> <nameid> findname false
{ false 3 1 roll 0 1 3 index 2 getu16 1 sub
{ % Stack: false table id index
12 mul 6 add 2 index exch 12 getinterval
dup 6 getu16 2 index eq
{ % We found the name we want.
exch pop
% Stack: false table record
dup 10 getu16 2 index 4 getu16 add
1 index 8 getu16 4 -1 roll 3 1 roll getinterval exch
% Stack: false string record
% Check for 8- vs. 16-bit characters.
is2byte { string2to1 } if true null 4 -1 roll exit
}
if pop
}
for pop pop
} bind def
/is2byte % <namerecord> is2byte <bool>
{ dup 0 getu16
{ { pop true } % Apple Unicode
{ pop false } % Macintosh Script manager
{ 1 getu16 1 eq } % ISO
{ 1 getu16 1 eq } % Microsoft
}
exch get exec
} bind def
/string2to1 % <string2> string2to1 <string>
{ dup length 2 idiv string dup
0 1 3 index length 1 sub
{ 3 index 1 index 2 mul 1 add get put dup }
for pop exch pop
} bind def
/cmapformats mark
% Each procedure in this dictionary is called as follows:
% -mark- encodingtable <<proc>> -mark- glyphindices...
0 % Apple standard 1-to-1 mapping.
{ 6 256 getinterval { } forall
} bind
4 % Microsoft/Adobe segmented mapping.
{ /etab exch def
/nseg2 etab 6 getu16 def
14 /endc etab 2 index nseg2 getinterval def
% The Apple TrueType documentation omits the 2-byte
% 'reserved pad' that follows the endCount vector!
2 add
nseg2 add /startc etab 2 index nseg2 getinterval def
nseg2 add /iddelta etab 2 index nseg2 getinterval def
nseg2 add /idroff etab 2 index nseg2 getinterval def
% The following hack allows us to properly handle
% idiosyncratic fonts that start at 0xf000:
/firstcode startc 0 getu16 16#ff00 and def
pop 0 2 nseg2 3 sub
{ /i2 exch def
/scode startc i2 getu16 def
counttomark scode firstcode sub 256 min exch sub 0 max { 0 } repeat
/ecode endc i2 getu16 def
/delta iddelta i2 getu16 def
idroff i2 getu16 dup 0 eq
{ pop scode 1 ecode { delta add 65535 and } for
}
{ % The +2 is for the 'reserved pad'.
/gloff exch 14 nseg2 3 mul add 2 add i2 add add def
0 1 ecode scode sub
{ 2 mul gloff add etab exch getu16
dup 0 ne { delta add 65535 and } if
}
for
}
ifelse
}
for
} bind
6 % Single interval lookup.
{ dup 6 getu16 { 0 exch } repeat
dup 8 getu16 0 exch 1 exch 1 sub
{ 2 mul 10 add 2 copy getu16 exch pop exch }
repeat pop
} bind
.dicttomark readonly def % cmapformats
/cmaparray % <cmaptab> cmaparray -mark- <glyphs> ...
{ mark exch dup 0 getu16 cmapformats exch .knownget
{ exec }
{ (Can't handle format ) print 0 getu16 = flush
0 1 255 { } for
}
ifelse
} bind def
/postformats mark
% Each procedure in this dictionary is called as follows:
% posttable <<proc>> glyphencoding
16#00020000 % Detailed map, required by Microsoft fonts.
{ /postglyphs exch def
postglyphs 32 getu16 /numglyphs exch def
/glyphnames numglyphs 2 mul 34 add def
[ 0 1 numglyphs 1 sub
{ 2 mul 34 add postglyphs exch getu16
dup 258 lt
{ MacGlyphEncoding exch get
}
{ 258 sub glyphnames exch
{ postglyphs 1 index get 1 add add }
repeat
1 add postglyphs exch 2 copy 1 sub get getinterval cvn
}
ifelse
}
for ]
} bind
.dicttomark readonly def % postformats
.dicttomark readonly def % .loadttfontdict
/.loadttfonttables % <file> .loadttfonttables -
% Pushes .loadttfontdict & scratch dict on d-stack,
% defines f, offsets, tables
{ .loadttfontdict begin
40 dict begin
/f exch def
/offsets f 12 string readstring pop def
/tables f offsets 4 getu16 16 mul string readstring pop def
} bind def
/.readsfnts0 { % <len0> .readsfnts0 <string>
dup string
dup 0 offsets putinterval
dup offsets length tables putinterval
dup offsets length tables length add
% Stack: len0 str str off+tab
3 index 1 index sub getinterval
f exch dup length 0 ne { readstring } if pop pop
exch pop
} bind def
/.dividesfnts { % <length> .dividesfnts -
(glyf) findtableentry pop
dup 8 getu32 /len0 exch def
12 getu32 /len1 exch def
len0 len1 add sub /len2 exch def
/sfnts [
len0 .readsfnts0
len1 dup maxstring gt
{ % Bad news: we'll have to split the glyfs.
% Right now we only provide for splitting into 2 parts,
% but we could generalize this without too much trouble.
f maxstring string readstring pop
exch maxstring sub
}
if string f exch readstring pop
len2 0 ne { f len2 string readstring pop } if
] def
/head (head) findtable pop def
len1 maxstring gt
{ % Determine where to split the glyfs by scanning loca.
% The very last entry in loca may be bogus.
% What a nuisance!
(loca) findtable pop dup length
head 50 getu16 0 ne
{ % 32-bit loca
8 sub -4 0
{ 1 index exch getu32 dup maxstring le { exch pop exit } if pop }
}
{ % 16-bit loca
4 sub -2 0
{ 1 index exch getu16 1 bitshift dup maxstring le { exch pop exit } if pop }
}
ifelse for
% Now the top element of the stack is the length of
% the first glyf string.
sfnts 1 get dup 0 3 index getinterval
sfnts exch 1 exch put
exch 1 index length 1 index sub getinterval
sfnts 2 get concatstrings sfnts exch 2 exch put
}
if
} bind def
/.makesfnts % - .makesfnts -
% Defines head, sfnts
{ % Find the end of the last table, and also the end of
% the last table below the 64K mark.
0 8 16 tables length
{ % Stack: end toffset
DEBUG
{ tables 1 index 8 sub 4 getinterval print ( ) print
tables 1 index getu32 =only ( ) print
tables 1 index 4 add getu32 =
}
if
tables 1 index getu32 exch tables exch 4 add getu32 add max
}
for
dup maxstring le {
.readsfnts0
% Pad to even length if necessary, per Adobe specification.
dup length 2 mod 0 ne {
<00> concatstrings
} if
1 array astore /sfnts exch def
/head (head) findtable pop def
} {
% If the total length exceeds maxstring, divide the data
% into 2+n strings: before glyf, glyfs, after glyf
.dividesfnts
} ifelse
} bind def
/.loadttfont % <file> .loadttfont <type42font>
{ .loadttfonttables
.makesfnts
/upem head 18 getu16 def
(cmap) findtable pop
% The Apple cmap format is no help in determining the encoding.
% Look for a Microsoft table. If we can't find one,
% just use the first table, whatever it is.
dup 4 8 getinterval exch % the default
0 1 2 index 2 getu16 1 sub
{ 8 mul 4 add 1 index exch 8 getinterval
dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
}
for
% Stack: subentry table
/cmapsub 2 index def
exch 4 getu32 1 index length 1 index sub getinterval
/cmaptab exch def
% See if we have PostScript glyph name information.
/post (post) findtable not { null } if def
/glyphencoding post null eq
{ MacGlyphEncoding }
{ postformats post 0 getu32 .knownget
{ post exch exec }
{ MacGlyphEncoding }
ifelse
}
ifelse def
/checksum head 8 getu32 def
mark
/FontType 42
/FontMatrix matrix
/PaintType 0
/FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
(name) findtable
{ % Find the names from the 'name' table.
/names exch def
/FontName names 6 findname not { checksum 16 8 string cvrs } if
/FontInfo mark
names 0 findname { /Notice exch } if
names 1 findname { /FamilyName exch } if
names 4 findname { /FullName exch } if
names 5 findname { /Version exch } if
}
{ % No name table, fabricate a FontName.
/FontName checksum 16 8 string cvrs
/FontInfo mark
}
ifelse
% Stack: /FontInfo mark key1 value1 ...
post null ne
{ /ItalicAngle post 4 gets32 65536.0 div
/isFixedPitch post 12 getu32 0 ne
/UnderlinePosition post 8 gets16 upem div
/UnderlineThickness post 10 gets16 upem div
}
if
counttomark 0 ne
{ .dicttomark }
{ pop pop }
ifelse
/Encoding
cmaptab cmaparray
counttomark array astore { glyphencoding exch get } forall
counttomark 256 sub dup 0 ge
{ { pop } repeat }
{ neg { /.notdef } repeat }
ifelse ]
% Until we can compute the MD5 fingerprint,
% just use the precomputed checksum.
/XUID [orgXUID 42 checksum]
/CharStrings glyphencoding dup length dict
0 1 3 index length 1 sub
{ % Stack: glyphencoding dict index
2 index 1 index get 2 index 1 index known
{ pop pop }
{ 2 index exch 3 -1 roll put }
ifelse
}
for exch pop readonly
/sfnts sfnts
.dicttomark
end end dup /FontName get exch definefont
} bind def